

package com.wkq.util
import kotlinx.coroutines.*
import kotlinx.coroutines.flow.*
import java.util.concurrent.ConcurrentHashMap

/**
 * TimerUtil：基于 Kotlin 协程实现的定时工具类
 * 支持：倒计时、定时任务、暂停恢复、任务取消、作用域绑定等
 *
 * @Author: wkq
 * @Time: 2025/07/15
 */
object TimerUtil {

    // 存储任务对应的 Job，用于取消任务
    private val jobMap = ConcurrentHashMap<String, Job>()

    // 存储任务对应的剩余倒计时时间（毫秒）
    private val remainingTimeMap = ConcurrentHashMap<String, Long>()

    // 标记倒计时是否处于暂停状态
    private val isPausedMap = ConcurrentHashMap<String, Boolean>()

    // 默认作用域：Main 线程
    private val defaultScope = CoroutineScope(Dispatchers.Main)

    /**
     * 启动一个定时重复执行的任务（如：每隔几秒执行一次）
     *
     * @param taskId       任务唯一标识
     * @param delayMillis  延迟执行的时间（默认 0 毫秒）
     * @param intervalMillis 执行间隔（单位：毫秒）
     * @param scope        协程作用域（默认 Main）
     * @param repeatTimes  重复次数（-1 表示无限执行）
     * @param action       每次执行的操作
     */
    fun startIntervalTask(
        taskId: String,
        delayMillis: Long = 0L,
        intervalMillis: Long,
        scope: CoroutineScope = defaultScope,
        repeatTimes: Int = -1,
        action: suspend () -> Unit
    ) {
        stopTask(taskId)

        val job = scope.launch {
            if (delayMillis > 0) delay(delayMillis)
            var count = 0
            while (isActive) {
                action()
                count++
                if (repeatTimes > 0 && count >= repeatTimes) break
                delay(intervalMillis)
            }
        }

        jobMap[taskId] = job
    }

    /**
     * 启动一个支持暂停和恢复的倒计时任务
     *
     * @param taskId    任务唯一标识
     * @param totalTime 倒计时总时间（毫秒）
     * @param interval  每次 tick 的间隔（毫秒）
     * @param scope     协程作用域（默认 Main）
     * @param onTick    每次回调剩余时间（毫秒）
     * @param onFinish  倒计时完成回调
     */
    fun startCountdown(
        taskId: String,
        totalTime: Long,
        interval: Long,
        scope: CoroutineScope = defaultScope,
        onTick: ((Long) -> Unit)? = null,
        onFinish: () -> Unit
    ) {
        stopTask(taskId)

        remainingTimeMap[taskId] = totalTime
        isPausedMap[taskId] = false

        val job = scope.launch {
            flow {
                var remaining = totalTime
                emit(remaining)
                while (remaining > 0) {
                    delay(interval)
                    if (isPausedMap[taskId] == true) break
                    remaining -= interval
                    emit(remaining)
                }
            }
                .catch { it.printStackTrace() }
                .onCompletion {
                    if (isPausedMap[taskId] != true) {
                        onFinish()
                    }
                }
                .collect { remaining ->
                    remainingTimeMap[taskId] = remaining
                    onTick?.invoke(remaining)
                }
        }

        jobMap[taskId] = job
    }

    /**
     * 暂停一个正在执行的倒计时任务
     *
     * @param taskId 倒计时任务标识
     */
    fun pauseCountdown(taskId: String) {
        isPausedMap[taskId] = true
        jobMap[taskId]?.cancel()
    }

    /**
     * 恢复一个已暂停的倒计时任务
     *
     * @param taskId   倒计时任务标识
     * @param interval 倒计时间隔（毫秒）
     * @param scope    协程作用域
     * @param onTick   每次回调剩余时间
     * @param onFinish 倒计时完成回调
     */
    fun resumeCountdown(
        taskId: String,
        interval: Long,
        scope: CoroutineScope = defaultScope,
        onTick: ((Long) -> Unit)? = null,
        onFinish: () -> Unit
    ) {
        val remaining = remainingTimeMap[taskId] ?: return
        startCountdown(taskId, remaining, interval, scope, onTick, onFinish)
    }

    /**
     * 停止并移除指定任务
     *
     * @param taskId 任务标识
     */
    fun stopTask(taskId: String) {
        jobMap[taskId]?.cancel()
        jobMap.remove(taskId)
        remainingTimeMap.remove(taskId)
        isPausedMap.remove(taskId)
    }

    /**
     * 停止并清除所有任务
     */
    fun stopAllTasks() {
        jobMap.values.forEach { it.cancel() }
        jobMap.clear()
        remainingTimeMap.clear()
        isPausedMap.clear()
    }

    /**
     * 检查某个任务是否仍在运行中
     */
    fun isTaskRunning(taskId: String): Boolean {
        return jobMap[taskId]?.isActive == true
    }

    /**
     * 获取某个倒计时任务的剩余时间（毫秒）
     */
    fun getRemainingTime(taskId: String): Long? {
        return remainingTimeMap[taskId]
    }
}
